﻿using PaperMaster.Model;
using PaperMaster.Chess.ChessModel;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace PaperMaster.Chess.PieceSpace
{
    /// <summary>
    /// 棋子种类大全。
    /// </summary>
    public enum Piece
    {
        TestPiece0,
        TestPiece1,
        SamplePiece,
    }
    /// <summary>
    /// 属性烈度
    /// </summary>
    public enum ElementIntensity
    {
        None,
        Normal,
        Extreme
    }
    /// <summary>
    /// 棋子主人，包括玩家，敌方和环境
    /// </summary>
    public enum PieceOwner
    {
        None,
        Player,
        Opponent,
        Env
    }
    /// <summary>
    /// 用于描述一个棋子的基本属性。其具体值将根据类名从JSON文件中读取
    /// 其中，所有棋子默认的数据由ChessModel加载，因此该类的对象不可以直接生成，而要通过ChessModel.pieceFactory接口来制作
    /// </summary>
    public abstract class AbstractPieceModelBase
    {
        /// <summary>
        /// 棋子的页面控制器，没有的话就是NULL
        /// </summary>
        public PieceViewController viewController = null;
        /// <summary>
        /// 棋子主人
        /// </summary>
        public PieceOwner owner;
        /// <summary>
        /// 棋子种类，换句话说就是它的名字。
        /// </summary>
        public Piece pieceType;
        /// <summary>
        /// 棋子默认属性。
        /// </summary>
        public virtual ElementType elementType { get; set; }
        /// <summary>
        /// 棋子属性的程度
        /// </summary>
        public ElementIntensity elementIntensity;
        /// <summary>
        /// 棋子可转化的属性。
        /// </summary>
        public List<ElementType> convertibleElementTypes = new List<ElementType>();
        /// <summary>
        /// 默认消耗法力
        /// </summary>
        public int manaCost;
        protected int _atk;
        /// <summary>
        /// 攻击力
        /// </summary>
        public virtual int atk
        {
            get
            {
                return _atk;
            }
            set
            {
                _atk = value;
            }
        }
        protected int _range;
        /// <summary>
        /// 射程
        /// </summary>
        public virtual int range
        {
            get
            {
                return _range;
            }
            set
            {
                _range = value;
            }
        }
        protected int _hp;
        /// <summary>
        /// 生命值
        /// </summary>
        public virtual int hp
        {
            get
            {
                return _hp;
            }
            set
            {
                _hp = value;
            }
        }
        protected Vector2Int _Loc;
        public virtual Vector2Int Loc
        {
            get
            {
                return _Loc;
            }
            set
            {
                _Loc = value;
            }
        }
        public AbstractPieceModelBase()
        {
        }
    }
    /// <summary>
    /// 用于描述单个棋子的状态
    /// </summary>
    public abstract class PieceModelBase:AbstractPieceModelBase
    {
        IChessModel _chessModel;
        public IChessModel chessModel
        {
            get
            {
                if (_chessModel == null)
                {
                    _chessModel = ModelContainer.Get<IChessModel>();
                }
                return _chessModel;
            }
        }
        /// <summary>
        /// 本回合是否动过
        /// </summary>
        public bool Moved = false;

        public bool BeginMoved = false;
        /// <summary>
        /// 攻击力
        /// </summary>
        public override int atk
        {
            get
            {
                return DecorateAtk(_atk);
            }
            set
            {
                _atk = value;
            }
        }
        /// <summary>
        /// 射程
        /// </summary>
        public override int range
        {
            get
            {
                return DecorateRange(_range);
            }
            set
            {
                _range = value;
            }
        }
        /// <summary>
        /// 生命值
        /// </summary>
        public override int hp
        {
            get
            {
                return DecorateHp(_hp);
            }
            set
            {
                _hp = value;
            }
        }
        public override Vector2Int Loc
        {
            get
            {
                return _Loc;
            }
            set
            {
                _Loc = value;
            }
        }
        public PieceModelBase()
        {
        }
        public PieceModelBase(Piece piece)
        {
            pieceType = piece;
            LoadData();
        }
        protected void LoadData()
        {
            AbstractPieceModelBase model = chessModel.GetPieceModel(pieceType);
            manaCost = model.manaCost;
            elementType = model.elementType;
            atk = model.atk;
            hp = model.hp;
            range = model.range;
            convertibleElementTypes = new List<ElementType>();
            foreach(var content in model.convertibleElementTypes)
            {
                convertibleElementTypes.Add(content);
            }
        }

        #region 各类修饰器
        /// <summary>
        /// 自身独特的修饰器
        /// </summary>
        IntDecorator _atkDecorator = new IntDecorator();
        /// <summary>
        /// 修饰攻击力
        /// </summary>
        /// <param name="atk"></param>
        /// <returns></returns>
        protected virtual int DecorateAtk(int atk)
        {
            return _atkDecorator.Decorate(chessModel.DecorateAtk(atk, elementType, owner));
        }
        /// <summary>
        /// 自身独特的修饰器
        /// </summary>
        IntDecorator _hpDecorator = new IntDecorator();
        /// <summary>
        /// 修饰生命
        /// </summary>
        /// <param name="hp"></param>
        /// <returns></returns>
        protected virtual int DecorateHp(int hp)
        {
            return _hpDecorator.Decorate(chessModel.DecorateHp(hp, elementType, owner));
        }
        /// <summary>
        /// 自身独特的修饰器
        /// </summary>
        IntDecorator _rangeDecorator = new IntDecorator();
        /// <summary>
        /// 修饰射程
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        protected virtual int DecorateRange(int range)
        {
            return _rangeDecorator.Decorate(chessModel.DecorateRange(range, elementType, owner));
        }
        /// <summary>
        /// 自身独特的修饰器
        /// </summary>
        AttackDecorator _iatkDecorator = new AttackDecorator();
        /// <summary>
        /// 修饰发出的攻击
        /// </summary>
        /// <param name="atk"></param>
        /// <returns></returns>
        protected virtual IAttack DecorateIAtk(IAttack atk)
        {
            return _iatkDecorator.Decorate(chessModel.DecorateAtk(atk, elementType, owner));
        }
        /// <summary>
        /// 制作一个攻击
        /// </summary>
        /// <returns></returns>
        public virtual IAttack GetAtk() {
            IAttack iatk = new Attack();
            iatk.dmg = atk;
            iatk.scopeOfAttack = new List<Vector2Int>();
            int dir = 1;
            if (owner == PieceOwner.Opponent)
            {
                dir = -1;
            }
            int x = Loc.x;
            int y = Loc.y;
            IChessModel chessModel = ModelContainer.Get<IChessModel>();

            for (int i = 0; i < range; i += dir)
            {
                if (y + i >= chessModel.BoardWidth || y + i < 0)
                {
                    iatk.scopeOfAttack.Add(new Vector2Int(x, y + i));
                    break;
                }
                PieceControllerBase piece = chessModel.Board.v[y + i][x].Piece;

                if (piece != null && piece.model != this)
                {
                    if (piece.model.owner != owner)
                    {
                        iatk.scopeOfAttack.Add(new Vector2Int(x, y + i));
                    }
                    break;
                }
            }

            iatk.owner = owner;

            iatk = DecorateIAtk(iatk);
            return iatk;
        }
        #endregion
    }

    /// <summary>
    /// 单个棋子的控制器
    /// </summary>
    public class PieceControllerBase
    {
        /// <summary>
        /// 所用模型
        /// </summary>
        public AbstractPieceModelBase model;

        public PieceControllerBase()
        {

        }
        /// <summary>
        /// 根据model来创建控制器
        /// </summary>
        /// <param name="model"></param>
        public PieceControllerBase(AbstractPieceModelBase model)
        {
            this.model = model;
        }


        /// <summary>
        /// 在回合开始时执行的操作
        /// </summary>
        public virtual void BeginAct()
        {
            ((PieceModelBase)(model)).Moved = false;
            ((PieceModelBase)(model)).BeginMoved = true;
        }
        /// <summary>
        /// 在回合结尾时执行的操作
        /// </summary>
        public virtual void EndAct()
        {
            ((PieceModelBase)(model)).Moved = true;
            ((PieceModelBase)(model)).BeginMoved = false;
        }
        /// <summary>
        /// 移动指定偏移量
        /// </summary>
        /// <param name="pos"></param>
        protected virtual void Move(Vector2Int pos)
        {
            int dir = 1;
            if (model.owner == PieceOwner.Opponent)
            {
                dir = -1;
            }
            if (pos.x > 0)
            {
                for (int i = 0; i < pos.x; i++)
                {
                    Move(dir, 0);
                }
            }
            else if (pos.x < 0)
            {
                for (int i = 0; i < -pos.x; i++)
                {
                    Move(-dir, 0);
                }
            }
            if (pos.y > 0)
            {
                for (int i = 0; i < pos.y; i++)
                {
                    Move(0, dir);
                }
            }
            else if (pos.y < 0)
            {
                for (int i = 0; i < -pos.y; i++)
                {
                    Move(0, -dir);
                }
            }
        }
        /// <summary>
        /// 移动,请令dx，dy的绝对值小于等于1
        /// </summary>
        protected virtual void Move(int dx,int dy)
        {
            int dir = 1;
            if (model.owner == PieceOwner.Opponent)
            {
                dir = -1;
            }
            int ny = model.Loc.y + dy * dir;
            int nx = model.Loc.x + dx * dir;
            IChessModel chessModel = ((PieceModelBase)(model)).chessModel;
            if (nx >= 0 && nx < chessModel.BoardLength && ny >= 0 && ny < chessModel.BoardWidth)
            {
                if (chessModel.Board.v[ny][nx].Piece == null)
                {
                    model.viewController.Move(dx * dir, dy * dir);
                    chessModel.Board.v[model.Loc.y][model.Loc.x].Piece = null;
                    chessModel.Board.v[model.Loc.y][model.Loc.x].Type = ChessBlockType.None;
                    OnMove(dx * dir, dy * dir);
                    chessModel.Board.v[ny][nx].Piece = this;
                    chessModel.Board.v[ny][nx].Type = ChessBlockType.Piece;
                    model.Loc = new Vector2Int(nx, ny);
                }
            }
        }
        /// <summary>
        /// 向前一格
        /// </summary>
        public virtual void Forward()
        {
            Move(0, 1);
        }
        /// <summary>
        /// 向后一格
        /// </summary>
        public virtual void Back()
        {
            Move(0, -1);
        }
        /// <summary>
        /// 向左一格
        /// </summary>
        public virtual void Left()
        {
            Move(-1, 0);
        }
        /// <summary>
        /// 向右一格
        /// </summary>
        public virtual void Right()
        {
            Move(1, 0);
        }
        /// <summary>
        /// 朝某个方向移动时调用，注意每移动一次就调用一次
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        protected virtual void OnMove(int dx, int dy)
        {

        }
        /// <summary>
        /// 发出一次攻击
        /// </summary>
        public virtual void Attack()
        {
            IAttack atk = ((PieceModelBase)(model)).GetAtk();
            ChessBoardViewController.GetController().GiveAtk(atk);
            OnAttack();
        }
        /// <summary>
        /// 在攻击时调用
        /// </summary>
        protected virtual void OnAttack()
        {

        }
        /// <summary>
        /// 承受攻击
        /// </summary>
        public virtual void TakeAttack(IAttack atk)
        {
            model.hp -= atk.dmg;
            if (model.hp <= 0)
            {
                ModelContainer.Get<IChessModel>().Board.v[model.Loc.y][model.Loc.x].Piece = null;
                OnDead();
                MonoBehaviour.Destroy(model.viewController.gameObject);
            }
        }
        /// <summary>
        /// 亡语
        /// </summary>
        public virtual void OnDead()
        {

        }
    }
    /// <summary>
    /// 单个棋子的视图控制器
    /// </summary>
    public class PieceViewController : MonoBehaviour
    {
        public PieceControllerBase controller;
        /// <summary>
        /// 在Awake中调用
        /// </summary>
        protected virtual void Init()
        {
            if (controller != null)
            {
                if (controller.model != null)
                {
                    if (controller.model.viewController == null)
                    {
                        controller.model.viewController = this;
                    }
                }
            }
        }
        protected virtual void FrameFun()
        {
            if (_moving)
            {
                Vector3 pos = transform.position;
                pos += _dir * _speed * Time.deltaTime;
                transform.position = pos;
                if ((_target - pos).magnitude < 0.4f)
                {
                    _moving = false;
                }
            }
        }
        bool _moving = false;
        Vector3 _dir;
        Vector3 _target;
        float _speed = 30f;
        public virtual void Move(int dx,int dy)
        {
            IChessModel chessModel = ((PieceModelBase)(controller.model)).chessModel;
            Vector3 target = chessModel.Board.v[controller.model.Loc.y + dy][controller.model.Loc.x + dx].pos3d;
            Vector3 pos = transform.position;
            _dir = (target - pos).normalized;
            _target = target;
            _moving = true;
        }
    }

}